
#include <stdio.h>
#include <string.h>

#include "stm32l4xx.h"
#include "stm32l4xx_ll_bus.h"
#include "stm32l4xx_ll_rcc.h"
#include "stm32l4xx_ll_gpio.h"
#include "stm32l4xx_ll_lpuart.h"
#include "stm32l4xx_ll_usart.h"

#include "bsp.h"
#include "dbgUart.h"


//#define UART_RS485					LPUART1
//#define UART_RS485_IRQn				LPUART1_IRQn
//#define UART_RS485_IRQHandler 		LPUART1_IRQHandler

#define MODE_7_E_1								0
#define MODE_7_O_1								1
#define MODE_8_E_1								2
#define MODE_8_O_1								3
#define MODE_8_n_1								4
#define MODE_8_n_2								5


static const uint32_t tbl_baud_rs485[]={/*1200,4800,*/9600,19200,38400,57600,115200, 0};
static const char* tbl_fmt_rs485[]={" 7-E-1", " 7-O-1",  " 8-n-2", " 8-O-1", " 8-E-1", " 8-n-1", ""};

//typedef struct _UART_CFG{
//	uint16_t baud;		//9600/19200/38400/57600
//	uint8_t mode;		//
//	uint8_t sta;		//当前状态（0--关闭，1--打开）
//}UART_CFG;

//static UART_CFG uart_rs485_cfg={115200, MODE_8_n_1, 0};		//准备作废，使用para_xxx.



/*设置RS485的串口的波特率。
输入参数 baud: 波特率，如9600。
*/
static void bsp_uart_rs485_config_baud(uint32_t baud)
{
	uint32_t pclk1_clock;
	
	if(baud< 19200){	
		//使能HSI，并等待稳定。
		LL_RCC_HSI_Enable();
		while(0 == LL_RCC_HSI_IsReady()){}	//不能使用LL_RCC_IsActiveFlag_HSIRDY()。
			
		LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_HSI);
		pclk1_clock= 16000000;	//没找到更合适的函数，暂直接指定值。
	}
	else{
		LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_SYSCLK);
		pclk1_clock= 48000000;
	}	
	
	
	//QQ配置参数前，禁止串口。
	LL_LPUART_Disable(UART_RS485);
	
	pclk1_clock= LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE);		//QQ可以取代上面的直接赋值语句。
	LL_LPUART_SetBaudRate(UART_RS485, pclk1_clock, baud); 
	
	//配置参数前，禁止串口。
	LL_LPUART_Enable(UART_RS485);
	RS485_RX;
	
	//根据波特率，设定接收超时时间（暂统一）
	//modbus_recv_info.tmo_max= 500;	//500ms
}



/*设置RS485的串口的数据格式。
输入参数 format: 数据格式序号，如0 --> " 8-n-2"。
*/
static void bsp_uart_rs485_config_format(uint32_t format)
{
	//配置参数前，禁止串口。
	NVIC_DisableIRQ(UART_RS485_IRQn);
	LL_LPUART_Disable(UART_RS485);
	
	
	//const char* tbl_fmt_rs485[]={/*" 7-E-1", " 7-O-1",*/  " 8-n-2", " 8-O-1", " 8-E-1", " 8-n-1", ""};
	if(0){
	}
	else if(0 == strcmp(" 8-E-1", tbl_fmt_rs485[format]))
		LL_USART_ConfigCharacter(UART_RS485, LL_USART_DATAWIDTH_9B, LL_USART_PARITY_EVEN, LL_USART_STOPBITS_1);	//奇偶校验时，数据宽度须为9B。
	else if(0 == strcmp(" 8-O-1", tbl_fmt_rs485[format]))
		LL_USART_ConfigCharacter(UART_RS485, LL_USART_DATAWIDTH_9B, LL_USART_PARITY_ODD, LL_USART_STOPBITS_1);
	else if(0 == strcmp(" 8-n-1", tbl_fmt_rs485[format]))
		LL_USART_ConfigCharacter(UART_RS485, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);
	else if(0 == strcmp(" 8-n-2", tbl_fmt_rs485[format]))
		LL_USART_ConfigCharacter(UART_RS485, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_2);	//8-n-2是9B还是8B?
	else{
		//uartS("\nerr rs485 format");
	}
	
	
	//配置参数后，使能串口。
	LL_LPUART_Enable(UART_RS485);
	//NVIC_EnableIRQ(UART_RS485_IRQn);
	
	RS485_RX;
}



///*设置RS485的串口模式、波特率和当前状态。
//和
//*/
//void bsp_uart_rs485_config(uint8_t mode, uint16_t baud, uint8_t sta)
//{
//	uint32_t pclk1_clock;
////	uart_rs485_cfg.mode= mode;
////	uart_rs485_cfg.baud= baud;
////	uart_rs485_cfg.sta= sta;
//	
//	if(baud< 19200){	
//		//使能HSI，并等待稳定。
//		LL_RCC_HSI_Enable();
//		while(0 == LL_RCC_HSI_IsReady()){}	//不能使用LL_RCC_IsActiveFlag_HSIRDY()。
//			
//		LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_HSI);
//		pclk1_clock= 16000000;	//没找到更合适的函数，暂直接指定值。
//	}
//	else{
//		LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_SYSCLK);
//		pclk1_clock= 48000000;
//	}	
//	
//	
//	//配置参数前，禁止串口。
//	NVIC_DisableIRQ(UART_RS485_IRQn);
//	LL_LPUART_Disable(UART_RS485);
//	
//	pclk1_clock= LL_RCC_GetUSARTClockFreq(LL_RCC_LPUART1_CLKSOURCE);		//QQ可以取代上面的直接赋值语句。
//	LL_LPUART_SetBaudRate(LPUART1, pclk1_clock, baud); 
//	
//	
//	//const char* tbl_fmt_rs485[]={/*" 7-E-1", " 7-O-1",*/  " 8-n-2", " 8-O-1", " 8-E-1", " 8-n-1", ""};
//	if(0){
//	}
//	else if(strcmp(" 8-E-1", tbl_fmt_rs485[mode]))
//		LL_USART_ConfigCharacter(UART_RS485, LL_USART_DATAWIDTH_9B, LL_USART_PARITY_EVEN, LL_USART_STOPBITS_1);	//奇偶校验时，数据宽度须为9B。
//	else if(strcmp(" 8-O-1", tbl_fmt_rs485[mode]))
//		LL_USART_ConfigCharacter(UART_RS485, LL_USART_DATAWIDTH_9B, LL_USART_PARITY_ODD, LL_USART_STOPBITS_1);
//	else if(strcmp(" 8-n-1", tbl_fmt_rs485[mode]))
//		LL_USART_ConfigCharacter(UART_RS485, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);
//	else if(strcmp(" 8-n-2", tbl_fmt_rs485[mode]))
//		LL_USART_ConfigCharacter(UART_RS485, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_2);
//	else{}
//		
////	if(MODE_7_E_1 == mode){
////		LL_LPUART_ConfigCharacter(LPUART1, LL_LPUART_DATAWIDTH_7B, LL_LPUART_PARITY_EVEN, LL_LPUART_STOPBITS_1);
////	}
////	else if(MODE_7_O_1 == mode){
////		LL_LPUART_ConfigCharacter(LPUART1, LL_LPUART_DATAWIDTH_7B, LL_LPUART_PARITY_ODD, LL_LPUART_STOPBITS_1);
////	}
////	else if(MODE_8_E_1 == mode){
////		LL_LPUART_ConfigCharacter(LPUART1, LL_LPUART_DATAWIDTH_9B, LL_LPUART_PARITY_EVEN, LL_LPUART_STOPBITS_1);
////	}
////	else if(MODE_8_O_1 == mode){
////		LL_LPUART_ConfigCharacter(LPUART1, LL_LPUART_DATAWIDTH_9B, LL_LPUART_PARITY_ODD, LL_LPUART_STOPBITS_1);
////	}
////	else if(MODE_8_n_1 == mode){
////		LL_LPUART_ConfigCharacter(LPUART1, LL_LPUART_DATAWIDTH_8B, LL_LPUART_PARITY_NONE, LL_LPUART_STOPBITS_1);
////	}
////	else if(MODE_8_n_2 == mode){
////		LL_LPUART_ConfigCharacter(LPUART1, LL_LPUART_DATAWIDTH_8B, LL_LPUART_PARITY_NONE, LL_LPUART_STOPBITS_2);
////	}
////	else{	//MODE_8_n_1
////		LL_LPUART_ConfigCharacter(LPUART1, LL_LPUART_DATAWIDTH_8B, LL_LPUART_PARITY_NONE, LL_LPUART_STOPBITS_1);
////	}
//	
//	
//	//配置参数后，使能串口。
//	LL_LPUART_Enable(UART_RS485);
//	//NVIC_EnableIRQ(UART_RS485_IRQn);
//	
//	RS485_RX;
//	
//	//根据波特率，设定接收超时时间（暂统一）
//	//modbus_recv_info.tmo_max= 500;	//500ms
//}



static void bsp_uart_rs485_hal(void)
{
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD);
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

	/*
	TXEN	Pin54/PD2	高电平时，数据在输出。
	TX	Pin30/PB11	LPUART1。
	RX	Pin29/PB10	LPUART1。
	*/
	LL_GPIO_SetPinOutputType(GPIOD, LL_GPIO_PIN_2,LL_GPIO_OUTPUT_PUSHPULL);
	LL_GPIO_SetPinMode(GPIOD, LL_GPIO_PIN_2, LL_GPIO_MODE_OUTPUT);
	RS485_RX;
	
	
	LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_11, LL_GPIO_MODE_ALTERNATE);
	LL_GPIO_SetAFPin_8_15(GPIOB, LL_GPIO_PIN_11, LL_GPIO_AF_8);				//C AF8 as L LPUART1_TX.
	
	LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_10, LL_GPIO_PULL_UP);
	LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_10, LL_GPIO_MODE_ALTERNATE);
	LL_GPIO_SetAFPin_8_15(GPIOB, LL_GPIO_PIN_10, LL_GPIO_AF_8);				//C AF8 as L LPUART1_RX.

}



/*配置MCU和BLE模块相连的串口。
输入参数 baud_idx: 波特率标志（非波特率数值，如0 --> 9600）
输入参数 format:   数据格式标志。（如0 --> "8-n-1"）

!!需要开启相应时钟。
*/
int32_t bsp_uart_rs485_init(uint32_t baud_idx, uint32_t format)
{
	bsp_uart_rs485_hal();
	
	LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
	LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_SYSCLK);	//PCLK as LPUART1's clock source,!!Must enable LPUART1_EN@RCC_APB1ENR2.
	
	LL_USART_Disable(UART_RS485);	//因为会动态修改该串口参数，所以假定它处于使能状态，需先禁止。
	

	bsp_uart_rs485_config_baud(tbl_baud_rs485[baud_idx]);
	bsp_uart_rs485_config_format(format);

	
	LL_USART_EnableDirectionTx(UART_RS485);
	LL_USART_EnableDirectionRx(UART_RS485);
	LL_USART_Enable(UART_RS485);
	
	LL_USART_EnableIT_RXNE(UART_RS485);
	
	
	/* preemption = 1, sub-priority = 1 */
	NVIC_SetPriority(UART_RS485_IRQn, 1);
	/* Enable Interrupt for UART0 channel */
	//NVIC_EnableIRQ(UART_RS485_IRQn);
	
	return 0;
}

/************************ END OF FILE ************************/
